package org.sith.taskrunner.ejb.transformers;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.sith.taskrunner.api.exceptions.TransformInputDataException;
import org.sith.taskrunner.api.transformer.InputDataTransofrmer;
import org.sith.taskrunner.api.user.Role;
import org.sith.taskrunner.api.user.User;
import org.sith.taskrunner.ejb.exceptions.ParseException;
import org.sith.taskrunner.util.UserImpl;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class UserXMLTransformer implements InputDataTransofrmer<UserInputData, InputStream> {
    private DocumentBuilderFactory builderFactory;
    private DocumentBuilder builder;
    private static final String LOGIN_TAG_NAME = "login";
    private static final String PASSWORD_TAG_NAME = "password";
    private static final String ROLE_TAG_NAME = "role";
    private static final String USER_TAG_NAME = "user";

    public UserXMLTransformer() {
        builderFactory = DocumentBuilderFactory
                .newInstance();
        try {
            builder = builderFactory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            throw new IllegalStateException("XML Configuration Error", e);
        }
    }

    private UserImpl parseUserTag(NodeList userProperties) throws ParseException {
        UserImpl user = new UserImpl();
        for (int j = 0; j < userProperties.getLength(); j++) {
            Node nodeProperty = userProperties.item(j);
            if (nodeProperty.getNodeType() != Node.ELEMENT_NODE) {
                continue;
            }
            Element element = (Element) nodeProperty;
            NodeList userParamValue = nodeProperty.getChildNodes();
            String paramValue = userParamValue.item(0).getNodeValue();
            if (element.getTagName().equals(LOGIN_TAG_NAME)) {
                user.setLogin(paramValue);
            } else if (element.getTagName().equals(PASSWORD_TAG_NAME)) {
                user.setPassword(paramValue);
            } else if (element.getTagName().equals(ROLE_TAG_NAME)) {
                Role role = toRole(paramValue);
                user.setRole(role);
            }
        }
        return user;
    }

    private NodeList getRootNodeList(InputStream inputStream) throws IOException, SAXException {
        Document doc = builder.parse(inputStream);
        doc.getDocumentElement().normalize();
        return doc.getElementsByTagName(USER_TAG_NAME);
    }

    /**
     * Method that convert string value to enum
     *
     * @param roleName
     * @return
     * @throws ParseException
     */
    private Role toRole(final String roleName) throws ParseException {
        try {
            return Role.valueOf(roleName.toUpperCase());
        } catch (IllegalArgumentException e) {
            throw new ParseException(e);
        }


    }

	@Override
	public UserInputData transform(InputStream inputData)
			throws TransformInputDataException {
		 Map<String, User> userMap = new HashMap<String, User>();

	        try {
	            NodeList usersList = getRootNodeList(inputData);
	            for (int i = 0; i < usersList.getLength(); i++) {
	                Node userNode = usersList.item(i);
	                NodeList userProperties = userNode.getChildNodes();
	                UserImpl user = parseUserTag(userProperties);
	                userMap.put(user.getLogin(), user);
	            }
	        } catch (SAXException e) {
	            throw new TransformInputDataException("Sax Exception", e);
	        } catch (IOException e) {
	            throw new TransformInputDataException("IOException", e);
	        } catch (ParseException e) {
	            throw new TransformInputDataException(e);
	        }
	        return new UserInputData(userMap);
	}

}
